#ifndef LW_ARRAY_H
#define LW_ARRAY_H

#include <string>

/**
 * 1D Array.
 * Size specified at compile time.
 */
template<typename T, int size>
class Array {
protected:
	T a[size];
	static const std::string indexOutOfBoundsMessage;

public:
	/**
	 * Creates an array with the specified size.
	 */
	Array() {
	}

	/**
	 * Creates this array as a copy of the specified array.
	 */
	Array(const Array<T,size>& v) {
		if(this != &v) {
			for(int i=0; i<size; ++i) {
				this->a[i] = v.a[i];
			}
		}
	}

	/**
	 * Deletes this array and all internal created data.
	 */
	virtual ~Array() {
	}

	/**
	 * Returns the size of this array.
	 */
	constexpr int Size() {
		return size;
	}

	/**
	 * Returns the value referenced by the specified index.
	 */
    inline const T& operator[](int index) const {
        if (index >= 0 && index < size) {
            return a[index];
        }

        throw std::out_of_range(indexOutOfBoundsMessage);
    }

	/**
	 * Returns or sets the value referenced by the specified index.
	 */
	inline T& operator[](int index) {
		if (index >= 0 && index < size) {
			return a[index];
		}

		throw std::out_of_range(indexOutOfBoundsMessage);
	}

	/**
	 * Compares the this array with the specified array, value by value.
	 * Returns true if equal.
	 */
	bool operator==(const Array<T,size>& v) const {
		for(int i=0; i<size; ++i) {
			if(this->a[i] != v.a[i]) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Compares the this array with the specified array, value by value.
	 * Returns true if not equal.
	 */
	bool operator!=(const Array<T,size>& v) const {
		for(int i=0; i<size; ++i) {
			if(this->a[i] != v.a[i]) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Assignes the specified array to this array, value by value.
	 */
	Array<T,size>& operator=(const Array<T,size>& v) {
		if(this != &v) {
			for(int i=0; i<size; ++i) {
				this->a[i] = v.a[i];
			}
		}

		return *this;
	}
};

template<typename T, int size>
const std::string Array<T,size>::indexOutOfBoundsMessage = "Array index out of range";

#endif //LW_ARRAY_H
